﻿using BaseTool;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace Airthmetic
{
    /// <summary>
    /// 棋盘格工具
    /// </summary>
    public class CheckerboardImageTool
    {
        /// <summary> 棋盘格参数 </summary>
        [XmlElement]
        private CheckerboardImageParam Param = new CheckerboardImageParam();

        #region 属性
        /// <summary> 一格像素长度 </summary>
        public int OneGridPixelWidth { get { return Param.OneGridPixelWidth; } set { Param.OneGridPixelWidth = value; } }
        /// <summary> 一格实际长度（mm） </summary>
        public double OneGridActualLength { get { return Param.OneGridActualLength; } set { Param.OneGridActualLength = value; } }

        /// <summary> 棋盘格横向单元格数量 </summary>
        public int BoardSizeWidth { get { return Param.BoardSizeWidth; } set { Param.BoardSizeWidth = value; } }
        /// <summary> 棋盘格纵向单元格数量 </summary>
        public int BoardSizeHeight { get { return Param.BoardSizeHeight; } set { Param.BoardSizeHeight = value; } }

        /// <summary> 棋盘格分辨率 </summary>
        public int ImagePixelWidth { get { return BoardSizeWidth * OneGridPixelWidth; } }
        /// <summary> 棋盘格分辨率 </summary>
        public int ImagePixelHeight { get { return BoardSizeHeight * OneGridPixelWidth; } }
        /// <summary>  棋盘格的实际长度 </summary>
        public double ImageActualWidth { get { return BoardSizeWidth * OneGridActualLength; } }
        /// <summary> 棋盘格的实际高度 </summary>
        public double ImageActualHeight { get { return BoardSizeHeight * OneGridActualLength; } }

        /// <summary>
        /// 返回打印分辨率PPI，建议在300+
        /// </summary>
        public int PPI
        {
            get
            {
                double mmToIn = 0.0393700787;
                return (int)Math.Floor(
                    Math.Sqrt(Math.Pow(ImagePixelWidth, 2) + Math.Pow(ImagePixelHeight, 2)) /
                    Math.Sqrt(Math.Pow(ImageActualWidth, 2) + Math.Pow(ImageActualHeight, 2)) / mmToIn);
            }
        }
        #endregion

        #region 初始化、参数读取\写入
        /// <summary>
        /// 构造
        /// </summary>
        public CheckerboardImageTool() { }
        /// <summary>
        /// 读取
        /// </summary>
        public void Read()
        {
            try
            {
                if (!File.Exists(PathTool.CheckerboardImageXml))
                {
                    Param = new CheckerboardImageParam();
                    Save();
                }
                Param = (CheckerboardImageParam)FileTool.ReadXML(PathTool.CheckerboardImageXml, typeof(CheckerboardImageParam));
                Log.SaveLog($"读取棋盘格工具参数成功", LogType.Run, Color.Black);
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"读取棋盘格工具参数异常，{ex.Message}");
            }
        }
        /// <summary>
        /// 写入
        /// </summary>
        public bool Save()
        {
            try
            {
                bool isok = FileTool.WriteXML(PathTool.CheckerboardImageXml, Param);
                Log.SaveLog($"保存棋盘格工具参数{(isok ? "成功" : "失败")}", LogType.Run, isok ? Color.Black : Color.Red);
                return isok;
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"保存棋盘格工具参数异常，{ex.Message}");
                return false;
            }
        }
        #endregion

        #region 方法
        /// <summary>
        /// 生成并保存棋盘格图像
        /// </summary>
        /// <returns></returns>
        public bool Generate()
        {
            try
            {
                DateTime now = DateTime.Now;

                Mat mat;
                Generate(out mat);

                FileInfo fi = new FileInfo($"{PathTool.DataCheckerBoardImagePath}CheckerBoard_" +
                    $"{BoardSizeWidth}x{BoardSizeHeight}-{OneGridActualLength}mm_" +
                    $"{now.ToString("yyyyMMdd_HHmmss")}.png");
                if (!fi.Directory.Exists)
                    fi.Directory.Create();
                Cv2.ImWrite(fi.FullName, mat);

                Log.SaveLog($"保存棋盘格成功，路径：{fi.FullName}", LogType.Run, Color.Black);
                return true;
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"保存棋盘格异常，{ex.Message}", LogType.Run);
                return false;
            }
        }
        /// <summary>
        /// 生成棋盘格图像
        /// </summary>
        /// <param name="mat"> 输出棋盘格图像 </param>
        /// <returns></returns>
        public bool Generate(out Mat mat)
        {
            try
            {
                int perBoardPixel = ImagePixelHeight / BoardSizeHeight;
                int basisHeight = (ImagePixelHeight - perBoardPixel * BoardSizeHeight) / 2;
                int basisWidth = (ImagePixelWidth - perBoardPixel * BoardSizeWidth) / 2;
                if (basisHeight < 0 || basisWidth < 0)
                {
                    mat = null;
                    return false;
                }

                mat = new Mat(ImagePixelHeight, ImagePixelWidth, MatType.CV_8UC1, Scalar.All(255));
                int flag;
                for (int j = 0; j < BoardSizeHeight; j++)
                {
                    for (int i = 0; i < BoardSizeWidth; i++)
                    {
                        flag = (i + j) % 2;
                        if (flag == 0)
                        {
                            for (int n = j * perBoardPixel; n < (j + 1) * perBoardPixel; n++)
                                for (int m = i * perBoardPixel; m < (i + 1) * perBoardPixel; m++)
                                    mat.At<byte>(n + basisHeight, m + basisWidth) = 0;
                        }
                    }
                }

                Log.SaveLog($"生成棋盘格成功", LogType.Run, Color.Black);
                return true;
            }
            catch (Exception ex)
            {
                Log.SaveError(ex, $"生成棋盘格异常：{ex.Message}", LogType.Run);
                mat = null;
                return false;
            }
        }
        /// <summary>
        /// 获取Bitmap图像
        /// </summary>
        /// <returns></returns>
        public Image GetImage()
        {
            try
            {
                Mat mat;
                if (!Generate(out mat))
                    return null;

                return mat.ToBitmap();
            }
            catch (Exception ex)
            {
                Log.SaveError(ex);
                return null;
            }
        }
        #endregion
    }

    /// <summary>
    /// 棋盘格图像参数
    /// </summary>
    [Serializable]
    public class CheckerboardImageParam
    {
        /// <summary> 一格像素长度 </summary>
        public int OneGridPixelWidth = 200;
        /// <summary> 一格实际长度（mm） </summary>
        public double OneGridActualLength = 10;

        /// <summary> 棋盘格横向单元格数量 </summary>
        public int BoardSizeWidth = 12;
        /// <summary> 棋盘格纵向单元格数量 </summary>
        public int BoardSizeHeight = 9;
    }
}
